/*Copyright 2009-2010 by Ward, David J ( pymethius@ominian.net )
Licensed work, all rights reserved.*/
/*
    Author: Ward, David J.
    Library: Signal Line
    Purpose: Provide a foundation for WM to shuttle the rest of the payload in.
    
        When two ships running at sea want to physically join together, they manuever to within a distance where
        a signal line can be thrown/shot over to the other ship.  This signal line is then tied to a thicker rope or wire and
        pulled back.  This process repeats, each time a thicker line is shuttled back and forther until you've got a good
        strong line linking each other.
        
    TODO remove this later:
       SuperUser account 'abyss':'llR9s45tuQV6'
       PlayerUser acct   'tester':'[ass403d'
       
*/

//Setup our namespaces
Ext.namespace("wm");
Ext.namespace("wmlib");



/*##############################################*/
//NetString Protocol
/*##############################################*/
wmlib.NetStringReceiver = function () {
        
    /**
     *Implementor: Ward, David J
     *Author: See notes
     *
     *Javascript clone of twisted.protocols.basic.NetStringReceiver
     *  This uses djb's Netstrings protocol to break up the input into strings.
     *  @see http://cr.yp.to/proto/netstrings.txt
     *
     *  Each string makes a callback to stringReceived, with a single
     *  argument of that string.
     *
     *  Security features:
     *  1. Messages are limited in size, useful if you don't want someone
     *  sending you a 500MB netstring (change MAX_LENGTH to the maximum
     *  length you wish to accept).
     *  2. The connection is lost if an illegal message is received.
     *
     */
    var self = this,
        conn = null,    
        LENGTH = 0,
        DATA = 1,
        COMMA = 2;
        
    var NUMBER = /(\d*)(:?)/,
        _readerState = LENGTH,
        _readerLength = 0,
        __buffer = '',
        __data = '';    
    
    self.DEBUG = false;
    self.MAX_LENGTH = 99999;
        

    /**
     *To keep the protocol 
     *
     */
    self.stringReceived = function(){ alert("stringReceived: Not implemented in NSR, must be assigned from elsewhere");};
    //self.write = function(){ alert("write: Not implemented in NSR, must be assigned from elsewhere");};
        /**
        Override this.
        */
        

    var doData = function(){
                
        var buffer = __data.slice(0, _readerLength);
                
        __data   = __data.slice(_readerLength);
                
        _readerLength = _readerLength - buffer.length;
        
        __buffer = __buffer + buffer;
        
        
        if( _readerLength !== 0 ){
            return;
        }
        wmlog.debug("Dispatching message from server ", __buffer);
        read(__buffer);        
        _readerState = COMMA
    }

    var doComma = function(){        
        _readerState = LENGTH;
                
        if ( __data.charAt(0)  !== ',' ){
            throw Exception("Missing comma")                        
        }        
        __data = __data.slice(1)        
    }

    var doLength = function(){
                        
        var m = __data.match(NUMBER);
                    
        if (! NUMBER.test(__data) ){
            throw Exception("Missing length")
        }
                
        __data = __data.slice(m[0].length);
        
        if( m[1].length > 0 ){            
            try{        
                _readerLength = _readerLength * (Math.pow(10,m[1].length) ) + parseInt(m[1]);
                        
            }catch(Exception){
                throw Exception("The server has apparently gone insane");
            }
            
            if( _readerLength > self.MAX_LENGTH){                
                throw  Exception("netstring too long");
            }
        }
        
        if( m[2].length > 0 ){        
            __buffer = ''
            _readerState = DATA
        }
    }

    self.dataReceived = function(data){
        __data = data
        try{
            while( __data.length > 0){
                if( _readerState == DATA){
                    doData();
                }
                else if( _readerState == COMMA){
                    doComma();
                }
                else if( _readerState == LENGTH){
                    try{
                        doLength();
                    }catch(lenErr){
                        wmlog.error("NSR.dataReceived_doLength() " , lenErr);
                    }
                }
                else{
                    throw Exception("mode is not DATA, COMMA, or LENGTH");
                    //raise RuntimeError, "mode is not DATA, COMMA or LENGTH"
                }
            }
        }catch(err){
            wmlog.error(err + " while in state " + _readerState)            
            brokenPeer = 1    
        }
        
    }
    var read = function(msg){
        wmlog.log("Processing message", msg);
        try{
            if(msg.isJSON()){
                msg = msg.evalJSON()
            }else{
                wmlog.error("Message corrupted",msg);
                throw Exception("Bad mojo");
            }
        }catch(e){
            wmlog.error("Message corrupted", msg)            
            return;
        }
        self.stringReceived(msg);
    }

    self.sendString = function(data){
        //self.transport.write('%d:%s,' % (len(data), data))
        return "" + data.length + ":" + data + ",";
    }
}
/* ################### */


wmlib.Signal = function(){
    var self = this;
    
    var conn = null;
    var nsr = null;
    //Yes, I want this exposed globablly
    window.wm.router = new wmlib.router();    
    
    //Using 4747 - Unofficial P2P port, should spook the hell out of the System admin's
    self.PORT = "4747";
    self.ADDR = "localhost";
    
    self.onClose = function(what){
        wmlog.log("Lost connection", what);
        if (confirm("Connection was lost, attempt to reconnect?")){
            conn.reset()
            self.connect()
        }
    }
    
    self.onOpen = function(){        
        wmlog.log("Connection made");
    }
    
    
    self.onRead = function(msg){
        wmlog.log("Server says ", msg);
        /**
         *This is not the method you think it is
         */
    }
    
    var doWrite = function(msg){
        conn.send(nsr.sendString(Object.toJSON(msg)));
    };
        
    self.connect = function(){        
        wmlog.log("Connection process started");
        nsr = new wmlib.NetStringReceiver();        
        nsr.stringReceived = wm.router.route;
        wm.router.doWrite = doWrite;
        
        conn = new self.transport();        
        conn.onread = nsr.dataReceived;
        conn.onclose = self.onClose;
        conn.onopen = self.onOpen;
        
        //PULLL THE STRINGS!!! PULL THE STRINGS!!!
        conn.open(self.ADDR, self.PORT);
    }
    
}

wmlib.Signal.prototype.transport = TCPSocket;

